#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <functional>
#include "Thread.hpp"
#include <string>
#include <unistd.h>
#include "Task.hpp"
#include "Log.hpp"
#include "LockGuard.hpp"

const int gdefalut = 5;
using namespace log_ns;

template <class T>
class ThreadPool
{

    typedef MyThread::Thread Thread;
    using func_t = std::function<void *(const std::string &)>;

private:
    void Lock()
    {
        pthread_mutex_lock(&_task_queue_mutex);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&_task_queue_mutex);
    }
    void CondWait()
    {
        pthread_cond_wait(&_task_queue_cond, &_task_queue_mutex);
    }
    void WakeUp()
    {
        pthread_cond_signal(&_task_queue_cond);
    }
    void WakeUpAll()
    {
        pthread_cond_broadcast(&_task_queue_cond);
    }

    bool IsEmpty()
    {
        return _task_queue.empty();
    }
    void *HandlerTask(const std::string &name)
    {

        while (true)
        {
            Lock();
            while (IsEmpty() && _isrunning)
            {
                _sleep_thread_num++;
                LOG(INFO, "%s sleep begin\n", name.c_str());
                CondWait();
                _sleep_thread_num--;
                LOG(INFO, "%s wakeup\n", name.c_str());
            }
            if (IsEmpty() && !_isrunning)
            {
                UnLock();
                break;
            }

            T &task = _task_queue.front();
            LOG(DEBUG, "%s get a task : %s\n", name.c_str(), task.Debug().c_str());
            _task_queue.pop();
            UnLock();
            task();
            LOG(DEBUG, "%s handler a task : %s\n", name.c_str(), task.Result().c_str());
        }
        return nullptr;
    }

    public:
    void init()
    {
        func_t func = std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1);
        _threads.reserve(_max_cap);
        for (int i = 0; i < _max_cap; i++)
        {
            std::string name = "thread-" + std::to_string(i + 1);
            _threads.emplace_back(name, func);
        }
    }

       ThreadPool(int max_cap = gdefalut) : _max_cap(max_cap), _isrunning(false)
    {
        LOG(INFO, "ThreadPool creat\n");

        pthread_mutex_init(&_task_queue_mutex, nullptr);
        pthread_cond_init(&_task_queue_cond, nullptr);
        //init();
        //start();
    }

    void start()
    {
        LOG(INFO, "ThreadPool start!\n");

        _isrunning = true;
        for (auto &thread : _threads)
        {
            thread.start();
        }
    }


public:
 
    void Equeue(T &task)
    {
        Lock();
        if (_isrunning)
        {
            _task_queue.push(task);

            if (_sleep_thread_num > 0)
                WakeUp();
        }
        UnLock();
    }

    void stop()
    {
        Lock();
        _isrunning = false;

        WakeUpAll();
        LOG(INFO, "ThreadPool stop!\n");

        UnLock();
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_task_queue_mutex);
        pthread_cond_destroy(&_task_queue_cond);
        LOG(INFO, "ThreadPool destroy\n");
    }

    // 单例模式
    // static ThreadPool<T> *GetThreadPoolPtr()
    // {

    //     if (_tp == nullptr)
    //     {
    //         LockGuard(_tp_mutex);
    //         if (_tp == nullptr)
    //         {
    //             _tp = new ThreadPool<T>;
    //             LOG(INFO, "the signal Threadpool is creater\n");
    //         }
    //         else
    //         {
    //             return _tp;
    //         }
    //     }
    //     return _tp;
    // }

private:
    int _max_cap;
    std::queue<T> _task_queue;
    std::vector<Thread> _threads;
    bool _isrunning;
    int _sleep_thread_num;

    pthread_mutex_t _task_queue_mutex;
    pthread_cond_t _task_queue_cond;

   // static ThreadPool<T> *_tp;
    //static pthread_mutex_t _tp_mutex;
};

// template <class T>
// ThreadPool<T> *ThreadPool<T>::_tp = nullptr;

// template <class T>
// pthread_mutex_t ThreadPool<T>::_tp_mutex = PTHREAD_MUTEX_INITIALIZER;